#!/bin/sh
#
# Copyright (c) 2008, 5V Technologies
#
# The command "tftp get" implementation (SBB S-WMTA/E-WMTA).
# For E-WMTA, see CPE specification, section 3.1.24.
#

# Note: Much of the essential content derived from /etc/init.d/auto_provision.sh
#
# Script arguments:
#  $1 - TFTP server
#  $2 - remote firmware image name

. /opt/cli2-scripts/common.sh

AUTOPROV_SCRIPT=/etc/init.d/auto_provision.sh
DEV_MSG=/dev/console
STATUS_FILE="/tmp/download_status.txt"

if [ -z "${TFTP}" ] || ! [ -x "${TFTP}" ]; then
	TFTP=$(for prog in /opt/firmware/sbin/tftp /bin/tftp; do if [ -x "$prog" ]; then echo "$prog"; exit 0; fi; done)
fi
#echo "Using ${TFTP}..."

[ -z "${TFTP_STDOUT_FILE}" ] && TFTP_STDOUT_FILE=/dev/null
[ -z "${TFTP_STDERR_FILE}" ] && TFTP_STDERR_FILE=/dev/null
#TFTP_STDOUT_FILE=/tmp/tftp_get-tftp.stdout
#TFTP_STDERR_FILE=/tmp/tftp_get-tftp.stderr

echo_error()
{
	local msg
	msg="$*"
	echo -n "${CRLF}${ERROR_PREFIX} ${msg}${CRLF}"
}

on_sighup() {
	logmsg "skip signal"
}

commit_updateimg() {
	updateimg=$1

	case $updateimg in
	0)
		fw_setenv sw_valid0 1
		fw_setenv sw_active0_ok 1
		fw_setenv sw_commit 0
		fw_setenv sw_tryactive 2
	;;
	1)
		fw_setenv sw_valid1 1
		fw_setenv sw_active1_ok 1
		fw_setenv sw_commit 1
		fw_setenv sw_tryactive 2
	;;
	esac
}

invalid_updateimg() {
	updateimg=$1

	case $updateimg in
	0)
		fw_setenv sw_valid0 0
		fw_setenv sw_active0_ok 0
		fw_setenv sw_commit 1   #useful when tryactive 1
	;;
	1)
		fw_setenv sw_valid1 0
		fw_setenv sw_active1_ok 0
		fw_setenv sw_commit 0   #useful when tryactive 0
	;;
	esac
}

update_image() {

	trap on_sighup SIGHUP
	cd /

	if grep "active=1" /proc/cmdline>/dev/null ; then
		#currentimg=1
		updateimg=0
	else
		#currentimg=0
		updateimg=1
	fi

	#check image valid
	[ ! -d /tmp/mountimg ] && mkdir /tmp/mountimg

	#remove zte header
	#if ! makebin -r $2; then
	#	logmsg "Can't find header $2 "
	#fi

	mount -o loop -rw -t squashfs  ${local_file} /tmp/mountimg
	if [ "$?" != "0" ]; then
		logmsg "mount image error"
		rm -r /tmp/mountimg
		rm -f  ${local_file}
		AUTOPROV_SCRIPT stop 2> /dev/null
		return 1
	fi

	### load checksum info ###
	if [ ! -f /tmp/mountimg/checksum.log ]; then
		AUTOPROV_SCRIPT stop 2> /dev/null
		return 1
	fi
	. /tmp/mountimg/checksum.log
	cp /tmp/mountimg/Rimage.squashfs /tmp
	
	# load image version info
	mkdir /tmp/IMG_VER
	mount -o loop -rw -t squashfs  /tmp/Rimage.squashfs /tmp/IMG_VER
	if [ "$?" != "0" ]; then
		logmsg "mount image error"
		rm -r /tmp/IMG_VER
		AUTOPROV_SCRIPT stop 2> /dev/null
		return 1
	fi
	new_version=$(cat /tmp/IMG_VER/opt/firmware/version)
	current_version=$(get_current_fw_version)

	umount /tmp/IMG_VER/
	rm -fr /tmp/IMG_VER
	rm /tmp/Rimage.squashfs
		
	# check md5sum
	Kimage_md5_now=`md5sum /tmp/mountimg/Kimage.lzma 2> /dev/null | cut -d' ' -f1`
	Rimage_md5_now=`md5sum /tmp/mountimg/Rimage.squashfs 2> /dev/null |cut -d' ' -f1`

	umount /dev/loop0 > /dev/null 2>&1
	umount /dev/loop1 > /dev/null 2>&1
	if [ -f /sbin/losetup ]; then
		losetup -d /dev/loop0 > /dev/null 2>&1
		losetup -d /dev/loop1 > /dev/null 2>&1
	fi
	umount -df /var/mountimg/ > /dev/null 2>&1

	rm -r /tmp/mountimg > /dev/null 2>&1
	if [ "$Kimage_md5_now" != "$Kimage_md5_org" -o "$Rimage_md5_now" != "$Rimage_md5_org" ]; then
		indicate_upgrade_failed "${local_file}" "firmware checksum error" > /dev/console
		logmsg "$(get_current_fw_version) Provision FirmUp Write Flash Fail[1]"
		AUTOPROV_SCRIPT stop 2> /dev/null
		return 1
	fi	
	
	# check image version
	if [ "$new_version" = "$current_version" ]; then
		indicate_upgrade_failed "${local_file}" "firmware version same" > dev/console
		logmsg "$(get_current_fw_version) Provision FirmUp Write Flash Fail[1]"
		AUTOPROV_SCRIPT stop 2> /dev/null
		return 1
	fi
	invalid_updateimg $updateimg

	if [ ! -f /usr/sbin/sw_download.sh ]; then
		#exit when x86
		rm -f  ${local_file}
		AUTOPROV_SCRIPT stop 2> /dev/null
		return 0;
	fi

	sh /usr/sbin/sw_download.sh end_download  ${local_file} $updateimg > /dev/null 2> /dev/null
	if [ "$?" != "0" ]; then
		logmsg "update error(error format or can't mount)"
		rm -f  ${local_file}
		AUTOPROV_SCRIPT stop 2> /dev/null
		return 1;
	fi

	commit_updateimg $updateimg
	AUTOPROV_SCRIPT stop 2> /dev/null
	(sleep 2; /sbin/reboot) &
}

get_current_fw_version()
{
	cat "${FIRMWARE_VERSION_FILE}"
}

logmsg() {
	# Facility 14 (14*8 = 112); severity 4:
	logger -p112.4 "$1"
}

indicate_upgrade_started()
{
	run_silent ${AUTOPROV_SCRIPT} mark_upgrade_in_progress
}

indicate_upgrade_failed()
{
	local local_file msg
	if [ -n "$1" ]; then
		local_file="$1"
		msg="$2"
		echo_error "${msg}"
		[ -n "${DEBUG_FW}" ] || ${RUN} rm -f "${local_file}"
	fi
	run_silent ${AUTOPROV_SCRIPT} unmark_upgrade_in_progress
}

#################

if ! indicate_upgrade_started; then
	echo_error "Another upgrade process already in progress"
	exit 1
fi

# $1 "${upgrade_server}"
# $2 "${image}"
# $3 "${local_file}"
# $4 "${timeout}"
# $5 "${retry_count}"
# $6 "${rerun_count}"
run()
{
	local upgrade_server image local_file timeout retry_count rerun_count rerun_counter  st error cli_error
	upgrade_server="$1"
	image="$2"
	local_file="$3"
	timeout="$4"
	# tftp option -R seem to mean total count of tries (not retries):
	retry_count="$(($5 + 1))"
	rerun_count="$6"
	rerun_counter=0

	# TODO - use the ${AUTOPROV_SCRIPT} to download with tftp:
	while [ "${rerun_counter}" -le "${rerun_count}" ]; do
		${TFTP} -g -T${timeout} -R${retry_count} -l "${local_file}" -r "${image}" "${upgrade_server}" 2>> "${TFTP_STDERR_FILE}" >> "${TFTP_STDOUT_FILE}"
		st="$?"
		if [ "${st}" = "0" -o "${st}" = "11" ]; then
			break
		fi
		rerun_counter=$(( ${rerun_counter} + 1 ))
		echo "Attempt ${rerun_counter}/${rerun_count} for tftp failed [status:${st}]..." >> "${TFTP_STDERR_FILE}"
	done

	#echo "${TFTP} exit status: ${st}" >> "${TFTP_STDERR_FILE}"
	if [ ${st} -ne 0 ]; then
		case "${st}" in
			14) error="Provision FirmUp Write Flash Fail[3]"; cli_error="network unreachable";;
			139) error="Provision FirmUp Write Flash Fail[1]"; cli_error="file not found";;
			12) error="Provision FirmUp Write Flash Fail[2]"; cli_error="failure writing file locally";;
			# Bugzilla#722: we are not allowed to change the CLI error message without
			#               permission. Therefore we still have the incorrect error
			#               message here (TFTP server side error[0]) which is very confusing.
		#       *)  error="Provision FirmUp Write Flash Fail[1]"; cli_error="communication failure[${st}]";;
			*)  error="Provision FirmUp Write Flash Fail[1]"; cli_error="TFTP server side error[${st}]";;
		esac
		indicate_upgrade_failed "${local_file}" "Firmware download failed: ${cli_error}"
		# BUG/BC#2190
		logmsg "$(get_current_fw_version) ${error}"

		######
		#echo "TFTP STDERR output:"
		#cat "${TFTP_STDERR_FILE}" | indent_stdin
		#echo "TFTP STOUT output:"
		#cat "${TFTP_STDOUT_FILE}" | indent_stdin
		AUTOPROV_SCRIPT stop 2> /dev/null
		exit 1
	fi
	if ! [ -s "${local_file}" ]; then
		indicate_upgrade_failed "${local_file}" "File empty"
		AUTOPROV_SCRIPT stop 2> /dev/null
		exit 1
	fi

#	if ! run_silent /opt/firmware/sbin/read_and_check "${local_file}"; then
#		indicate_upgrade_failed "${local_file}" "firmware checksum error"
#		logmsg "$(get_current_fw_version) Provision FirmUp Write Flash Fail[1]"
#		exit 1
#	fi

	# Check the name of the f/w image that it is what it claims to be:
#	if ! run_silent ${AUTOPROV_SCRIPT} check_imagename "${image}"; then
#		indicate_upgrade_failed "${local_file}" "mismatch between f/w image name and version"
		# No need to do logmsg here - taken care by the autoprovision.sh script...
#		exit 1
#	fi

	#[ -f /var/run/provision.start ] && rm -f /var/run/provision.start

	# Probably not necessary (any more):
#	ignore_hup()
#	{
#		true
#	}
#	trap ignore_hup HUP
	update_image
#	${AUTOPROV_SCRIPT} set_cli2_death_reason "Manual firmware upgrade" upgrade "${local_file}" > /tmp/auto_provision.stdout 2> /tmp/auto_provision.stderr &
	#echo "EXIT STATUS: $?"
}

firmware_download_dir=/tmp

upgrade_server="$1"
[ -z "${upgrade_server}" ] && \
	upgrade_server=`get_meta_value_or_default fupdate fupdate_tftp_image_server "upgrade server"`

image="$2"
[ -z "${image}" ] && \
	image=`get_meta_value_or_default fupdate fupdate_image_name "firmware file name"`
if [ -f "${FIRMWARE_VERSION_FILE}" ] && [ $(cat "${FIRMWARE_VERSION_FILE}") = "${image}" ]; then
	indicate_upgrade_failed
	echo "${ERROR_PREFIX} refuse to upgrade to the current f/w version"
	exit 0
fi

local_file="${firmware_download_dir}/BASS_WEB"
timeout=`get_meta_value_or_default fupdate fupdate_tftp_image_timeout "TFTP firmware upgrade timeout" 3`
retry_count=`get_meta_value_or_default fupdate fupdate_tftp_image_retry_count "TFTP firmware retry count" 4`
rerun_count=`get_meta_value_or_default fupdate fupdate_tftp_image_rerun_count "TFTP firmware rerun count" 2`

run "${upgrade_server}" "${image}" "${local_file}" "${timeout}" "${retry_count}" "${rerun_count}" &
